# coding: UTF-8
import torch
import torch.nn as nn
import torch.nn.functional as F
import numpy as np

class Config:
    def __init__(self,embedding="random",num_class=10,num_epochs=20):

        self.embedding_pretrained = torch.tensor(
            np.load(embedding)["embeddings"].astype('float32'))\
            if embedding != 'random' else None                                       # 预训练词向量
        print("===================================")
        print(type(self.embedding_pretrained))
        print(self.embedding_pretrained.shape)
        self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')  # 设备
        self.dropout = 0.5
        self.require_improvement = 2000 # 超过2000个batch没有提升就停止
        self.num_classes = num_class
        self.n_vocab = 3000  # 词表大小
        self.num_epochs = num_epochs
        self.batch_size = 128
        self.pad_size = 32
        self.learning_rate = 1e-3
        self.embed = self.embedding_pretrained.size(1)\
            if self.embedding_pretrained is not None else 300
        self.filter_sizes = (3, 4, 5)
        self.filter_size = 3
        self.num_filters = 250

class Model(nn.Module):
    def __init__(self,config):
        super(Model, self).__init__()
        if config.embedding_pretrained is not None:
            self.embedding = nn.Embedding.from_pretrained(config.embedding_pretrained, freeze=True)
        else:
            self.embedding = nn.Embedding(config.n_vocab, config.embed, padding_idx=config.n_vocab - 1)
        self.convs = nn.Conv2d(1,config.num_filters,(config.filter_size,config.embed))
        self.flatten = Flatten()
        self.fc1 = nn.Linear(config.num_filters * config.filter_size, 200)
        self.fc2 = nn.Linear(200,config.num_classes)

    def forward(self, x):
        x = x[1]

        out = self.embedding(x)
        out = out.unsqueeze(out)

        out = self.convs(out)
        out = F.relu(out).squeeze(3)
        out = F.max_pool1d(out,out.size(2)).squeeze(2)

        out = self.flatten(out)
        out = self.fc1(out)
        out = self.fc2(out)
        return out


class Flatten(nn.Module):
    def __init__(self):
        super(Flatten,self).__init__()

    def forward(self,x):
        shape = torch.prod(torch.tensor(x.shape[1:])).item()
        # -1 把第一个维度保持住
        return x.view(-1,shape)

if __name__ == '__main__':
    config =Config()
    model = Model(config)
    print(model)